package cn.akwangl.controller;

import cn.hutool.core.io.IoUtil;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * 文件相关API.
 *
 * @author youyongkun
 * @date 2022/5/17 11:07
 * @since 0.0.2
 */
@RestController
@RequestMapping("/file")
public class FileController {

    @GetMapping("/download")
    public void download(HttpServletResponse response) throws IOException {
        File file = ResourceUtils.getFile("classpath:download/openresty-1.19.9.1-win64.zip");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/vnd.ms-excel; charset=utf-8");
        String percentEncodedFileName =
                URLEncoder.encode(file.getName(), "utf-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename=" + percentEncodedFileName + ";filename*=utf-8''" + percentEncodedFileName);
        ServletOutputStream outputStream = response.getOutputStream();
        FileInputStream inputStream = new FileInputStream(file);
        IoUtil.copy(inputStream, outputStream);
        outputStream.flush();
        response.flushBuffer();
    }

    /**
     * SpringBoot 上传文件流程
     * <p>
     * 在项目启动时,容器会初始化一个{@link MultipartConfigElement}对象Bean.在这个Bean中
     * location 为 null
     * maxFileSize 为 10485760 字节
     * maxRequestSize 为 10485760 字节
     * fileSizeThreshold 为 0.
     * <p>
     * 当然也可以在容器中创建一个{@link org.springframework.context.annotation.Configuration} 的配置类,进行配置.
     * 也可以在yml通过以下属性配置{@link  MultipartProperties}.
     * <pre>
     * spring:
     *   servlet:
     *      multipart:
     *        file-size-threshold: 0
     *        max-file-size: 1MB
     *        max-request-size: 1MB
     * </pre>
     * <p>
     * 以上是修改{@link MultipartConfigElement}属性配置,修改属性配置也会对代码逻辑有所变化.
     * 在一个请求过来时,先会经过{@link DispatcherServlet#doDispatch(HttpServletRequest, HttpServletResponse)}方法.
     * 在这个方法中会判断HTTP 请求方式等,当然这个方法判断的东西很多.我们只需要关系上传相关的代码,重点关注{@link DispatcherServlet#checkMultipart(HttpServletRequest)}
     * 方法.
     * <p>
     * 以下分析全部都是默认实现类{@link StandardServletMultipartResolver}
     * {@link DispatcherServlet#checkMultipart(HttpServletRequest)} 方法
     * 1. 首先会判断是否 {@link MultipartResolver#isMultipart(HttpServletRequest)} 处理类,这个判断时通过http请求头来判断的
     * 2. 如果返回true则开始进行文件解析{@link MultipartResolver#resolveMultipart(HttpServletRequest)}
     * <p>
     * {@link MultipartResolver#resolveMultipart(HttpServletRequest)} 方法其内部实现代码非常少,重点关注parseRequest方法
     * <p>
     * {@link StandardMultipartHttpServletRequest#parseRequest(HttpServletRequest)} 代码会通过{@link HttpServletRequest#getParts()}方法,
     * 该方法注释也很明确的描述返回所有上传数据集合,所以这个方法就会用到上面配置的{@link MultipartConfigElement} Bean.其默认实现采用{@link RequestFacade}类.
     * <p>
     * 重点来了{@link Request#parseParts(boolean)}
     * 1. 首先获取{@link MultipartConfigElement}Bean 如果通过上方的修改入口会对其属性值发生变化.
     * 2. 获取location会有几种判断,如果为null则使用{@link ServletContext.TEMPDIR}默认目录
     * 3. 不为null则使用{@link ServletContext.TEMPDIR}+location构建目录
     * 4. 判断目录存不存在,不存在则创建
     * 5. 另外开始判断文件请求最大值和文件最大值
     *
     * @param multipartFile 上传文件
     * @author 阿坤同学
     * @date 2022-12-30 16:00
     */
    @PostMapping("/upload")
    public void upload(@RequestParam("file") MultipartFile multipartFile) {
        System.out.println();
    }
}
